import random
import tkinter as tk
from tkinter import ttk, messagebox
from serial import Serial, SerialException
import threading
import queue
import time
from node_data_manage import NodeDataManager


class NodeMonitorApp:
    def __init__(self, master):
        self.master = master
        master.title("节点监控系统")

        # 初始化数据管理器
        self.data_manager = NodeDataManager()



        # 界面初始化
        self.create_menu()
        self.create_widgets()
        #self.setup_serial_connections()
        self.start_update_loop()

    def create_menu(self):
        """创建顶部菜单栏"""
        menubar = tk.Menu(self.master)



        # 设置菜单
        settings_menu = tk.Menu(menubar, tearoff=0)
        settings_menu.add_command(label="串口设置", command=self.show_serial_settings)
        menubar.add_cascade(label="设置", menu=settings_menu)

        self.master.config(menu=menubar)

    def show_serial_settings(self):
        """显示串口设置对话框"""
        settings_win = tk.Toplevel(self.master)
        settings_win.title("串口设置")

        ttk.Label(settings_win, text="数据端口:").grid(row=0, column=0, padx=5, pady=5)
        self.data_port_entry = ttk.Entry(settings_win)
        self.data_port_entry.grid(row=0, column=1, padx=5, pady=5)
        self.data_port_entry.insert(0, "COM1")

        ttk.Label(settings_win, text="波特率:").grid(row=1, column=0, padx=5, pady=5)
        self.baudrate_entry = ttk.Entry(settings_win)
        self.baudrate_entry.grid(row=1, column=1, padx=5, pady=5)
        self.baudrate_entry.insert(0, "115200")

        ttk.Button(settings_win, text="应用", command=self.apply_serial_settings).grid(row=2, columnspan=2, pady=10)

    def apply_serial_settings(self):
        """应用新的串口设置"""
        new_port = self.data_port_entry.get()
        new_baud = int(self.baudrate_entry.get())

        # 断开现有连接
        if self.data_manager.serial_connected:
            self.data_manager.disconnect_serial()

        # 尝试新连接
        if self.data_manager.connect_serial(new_port, new_baud):
            threading.Thread(target=self.read_serial_data, daemon=True).start()
            messagebox.showinfo("提示", "串口设置已更新")
        else:
            messagebox.showerror("错误", "无法连接指定串口")

    def create_widgets(self):
        # 左侧参数面板
        left_frame = ttk.Frame(self.master, width=300)
        left_frame.pack(side=tk.LEFT, fill=tk.Y)

        # 节点参数表格
        self.tree = ttk.Treeview(left_frame, columns=("ID", "Position", "Status","Neighbors","Energy"), show="headings")
        self.tree.heading("ID", text="节点ID")
        self.tree.heading("Position", text="位置坐标")
        self.tree.heading("Status", text="状态")
        self.tree.heading("Neighbors", text="邻接点RSSI")
        self.tree.heading("Energy", text="电量")
        self.tree.pack(fill=tk.BOTH, expand=True)

        # 右侧主显示区
        right_frame = ttk.Frame(self.master)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

        # 拓扑图面板
        self.topology_canvas = tk.Canvas(right_frame, width=600, height=400, bg="white")
        self.topology_canvas.pack(fill=tk.BOTH, expand=True)

        # 视频显示面板
        self.video_label = ttk.Label(right_frame)
        self.video_label.pack(fill=tk.BOTH, expand=True)



    def read_serial_data(self):
        """持续读取串口数据"""
        while self.data_manager.serial_connected:
            try:
                raw_data = self.data_manager.serial_port.readline()
                if raw_data:
                    #串口输出典型为+NNMI:0001,-29,-111,360,xxx
                    parts = com_input.split(',') # 用“，”隔开
                    if len(parts) > 4:  # 只有数据所在的这一行会有4个逗号，从而取出报文
                    
                        result = check_packet(parts[4])#报文内容，解包函数check_packet另写
                        preaddress = parts[0][6:10]  # 模块自带上一跳地址

            except SerialException as e:
                print(f"串口读取错误: {str(e)}")
                self.data_manager.disconnect_serial()

    def start_update_loop(self):
        """启动界面更新循环"""
        self.update_gui()
        self.master.after(100, self.start_update_loop)

    def update_gui(self):
        """更新界面元素"""
        # 更新节点参数表格
        self.update_node_table()

        # 更新拓扑图
        self.draw_topology()

        # 更新视频流（需自行实现）
        # self.update_video()

    def update_node_table(self):
        """更新节点参数表格"""
        self.tree.delete(*self.tree.get_children())
        all_data = self.data_manager.get_all_data()

        for node_id, data in all_data.items():
            self.tree.insert("", "end", values=(
                node_id,
                f"({data['position'][0]:.2f}, " +
                f"{data['position'][1]:.2f}, " +
                f"{data['position'][2]:.2f})",
                data['status'],
                f"({', '.join(f'{elem:.2f}' for elem in data['neighbors rssi'])})",
                f"{data['energy']:.2f}"
            ))

    def draw_topology(self):
        """绘制节点拓扑图"""
        self.topology_canvas.delete("all")
        node_positions = {
            # i:(self.data_manager.nodes[i]["position"][0],
            #    self.data_manager.nodes[i]["position"][1])
            # for i in range(self.data_manager.num_nodes)
            #后续可能可以改成实时位置显示，现在没有数据
            0: (100, 100),
            1: (400, 100),
            2: (250, 250),
            3: (100, 400),
            4: (400, 400)
        }

        all_data = self.data_manager.get_all_data()

        # 绘制连接线
        connections = [(1, 2), (2, 3), (3, 4), (4, 0)]
        for a, b in connections:
            self.topology_canvas.create_line(
                node_positions[a][0], node_positions[a][1],
                node_positions[b][0], node_positions[b][1],
                width=2, fill="blue"
            )

        # 绘制节点
        for node_id, (x, y) in node_positions.items():
            status = all_data[node_id]["status"]
            status_color = "green" if status == "在线" else "red"
            self.topology_canvas.create_oval(
                x - 20, y - 20, x + 20, y + 20,
                fill=status_color, outline="black"
            )
            self.topology_canvas.create_text(
                x, y, text=str(node_id),
                font=("Arial", 12), fill="white"
            )

    def on_close(self):
        """关闭程序时的清理操作"""
        self.data_manager.disconnect_serial()
        self.master.destroy()

#测试函数，用于测试gui界面是否能根据参数变化而变化
def test_update(_NodeDataManager):
    while True:
        with _NodeDataManager.lock:
            _NodeDataManager.nodes[3]["position"][0] = random.random()
        time.sleep(1)

if __name__ == "__main__":
    root = tk.Tk()
    app = NodeMonitorApp(root)
    #threading.Thread(target=test_update, args=(app.data_manager,), daemon=True).start()
    root.protocol("WM_DELETE_WINDOW", app.on_close)
    root.mainloop()
